package org.pgis.core;

import java.awt.Color;
import java.awt.Dimension;
import java.awt.Toolkit;
import java.awt.event.MouseEvent;
import java.util.HashMap;
import java.util.Map;
import java.util.Vector;

import javax.swing.JPanel;

import org.pgis.entity.ConnectingLine;
import org.pgis.entity.Point3d;
import org.pgis.gui.MainWindow;

import vtk.vtkActor;
import vtk.vtkAxes;
import vtk.vtkLineSource;
import vtk.vtkPanel;
import vtk.vtkPointPicker;
import vtk.vtkPolyDataMapper;
import vtk.vtkSphereSource;
import vtk.vtkTextActor;
import vtk.vtkTubeFilter;

public abstract class AbstractScenePanel extends JPanel{

	private static final long serialVersionUID = 1L;
	private vtkPanel vtkPanel = new vtkPanel();
	private SurfaceImageModel sim;
	private Map<String, AbstractImageModel> actors = new HashMap<String, AbstractImageModel>();
	private vtkPointPicker pointPicker = new vtkPointPicker();
	private Vector<ConnectingLine> connectingLines = new Vector<ConnectingLine>(0);
    private int totalNumberOfPoints = 0;
    private vtkActor previousPointActor, currentPointActor;

	public AbstractScenePanel() {
		vtkPanel.setBackground(Color.LIGHT_GRAY);
		//this.add(vtkPanel);
		setDefaultPanelProperties();
		createAxisBarWithLetter();
		try {
			sim = new SurfaceImageModel();
			if(sim == null || sim.getActor() == null) {
				System.out.println("Exception in loading the image");
				return;
			}
			vtkPanel.GetRenderer().AddActor(sim.getActor());
			vtkPanel.GetRenderer().AddActor(sim.getOutlineActor());
			vtkPanel.GetRenderer().GetActiveCamera().SetFocalPoint(sim.getActor().GetOrigin());
			vtkPanel.GetRenderer().ResetCamera();
			vtkPanel.Render();
			vtkPanel.addMouseListener(new java.awt.event.MouseAdapter() {
		            public void mouseClicked(MouseEvent e) {PointPick(e);
		        }});

		        //drawCenterLine();

		    pointPicker.AddPickList(sim.getActor());
			add(vtkPanel);
		} catch (Exception e) {
			e.printStackTrace();
		}
	}

	private void PointPick (MouseEvent e) {

        int x=e.getX(), y=e.getY();
        Point3d point = new Point3d(x, vtkPanel.getHeight() - y, 0);
        double[] a;

        pointPicker.PickFromListOn();
        pointPicker.Pick(point.getX(), point.getY(), point.getZ(), vtkPanel.GetRenderer());

        int noOfPoints = pointPicker.GetPickedPositions().GetNumberOfPoints();
        //System.out.println("Number of Points: " + noOfPoints);
        vtkActor actor;
        for(int i = 0; i < noOfPoints; i++ ){
           a = pointPicker.GetPickedPositions().GetPoint(i);

           //System.out.println("* Point " + i + ":   "  + a[0] + ",  " + a[1] + ",  " + a[2]);
           actor = createActor(a[0], a[1], a[2], Color.red, "label");
           totalNumberOfPoints++;

           if(totalNumberOfPoints % 2 == 1) {
        	   previousPointActor = actor;
        	   //previousPoint = new Point3d(a[0], a[1], a[2]);
           } else {
        	   //currentPoint = new Point3d(a[0], a[1], a[2]);
        	   currentPointActor = actor;
        	   ConnectingLine cl = new ConnectingLine(previousPointActor, currentPointActor);
        	   drawLine(cl);
        	   connectingLines.add(cl);
        	   MainWindow.getInstance().updateConnectingLines(connectingLines);
           }


           }
        	System.out.println("\n");
        }

	private vtkActor createActor(double x, double y, double z, Color color, String id) {

    	vtkSphereSource ball = new vtkSphereSource();
        ball.SetThetaResolution(10);
        ball.SetPhiResolution(10);
        ball.SetRadius(1);

        vtkPolyDataMapper ballMapper = new vtkPolyDataMapper();
        ballMapper.SetInput(ball.GetOutput());

        vtkActor obj = new vtkActor();
        obj.SetMapper(ballMapper);
        obj.SetPosition(x, y, z);

        obj.GetProperty().SetRepresentationToSurface();

        obj.GetProperty().SetColor((float) color.getRed() / 255,
                (float) color.getGreen() / 255,
                (float) color.getBlue() / 255);

        obj.GetProperty().FrontfaceCullingOn();
        obj.GetProperty().BackfaceCullingOn();

        vtkPanel.GetRenderer().AddActor(obj);
        vtkPanel.Render();

        return obj;
        //pointPicker.AddPickList(obj);

    }

	private void drawLine(ConnectingLine cl) {

    	vtkLineSource line = new vtkLineSource();
    	line.SetPoint1(cl.getStartPoint().getX(), cl.getStartPoint().getY(), cl.getStartPoint().getZ());
    	line.SetPoint2(cl.getEndPoint().getX(), cl.getEndPoint().getY(), cl.getEndPoint().getZ());

    	vtkPolyDataMapper mapper = new vtkPolyDataMapper();
    	mapper.SetInput(line.GetOutput());

    	vtkActor obj = new vtkActor();
        obj.SetMapper(mapper);

        vtkPanel.GetRenderer().AddActor(obj);
        vtkPanel.Render();

    }

	private void setDefaultPanelProperties() {
		Dimension fullScreen = Toolkit.getDefaultToolkit().getScreenSize();

		vtkPanel.setSize(fullScreen.width - 320, fullScreen.height - 120);

		vtkPanel.GetRenderer().SetBackground(0.0, 0.0, 0.0);
		vtkPanel.GetRenderer().LightFollowCameraOn();
		vtkPanel.GetRenderer().GetActiveCamera().SetViewUp(0, 0, -1);
		vtkPanel.GetRenderer().GetActiveCamera().SetPosition(0, 1, 0);
		vtkPanel.GetRenderer().GetActiveCamera().ComputeViewPlaneNormal();
		//vtkPanel.GetRenderer().GetActiveCamera().SetFocalPoint(actor.GetOrigin());
		vtkPanel.GetRenderer().ResetCamera();
	}

	private void createAxisBarWithLetter() {

		int minV = Math.min(2, Math.min(2, 2));
		vtkAxes axes = new vtkAxes();
		axes.SetOrigin(0, 0, 0);
		axes.SetScaleFactor(minV);
		vtkTubeFilter axesTubes = new vtkTubeFilter();
		axesTubes.SetInput(axes.GetOutput());
		axesTubes.SetRadius(0.5);
		axesTubes.SetNumberOfSides(6);
		vtkPolyDataMapper axesMapper = new vtkPolyDataMapper();
		axesMapper.SetInput(axesTubes.GetOutput());
		vtkActor axesActor = new vtkActor();
		axesActor.SetMapper(axesMapper);
		vtkPanel.GetRenderer().AddActor(axesActor);

		// Text Actor
		vtkTextActor textActorX = new vtkTextActor();
		textActorX.SetInput("X");

		textActorX.GetTextProperty().SetColor(1, 0, 0);
		textActorX.GetTextProperty().ShadowOff();
		textActorX.GetPositionCoordinate().SetCoordinateSystemToWorld();
		textActorX.GetPositionCoordinate().SetValue(15, 0, 2);
		vtkPanel.GetRenderer().AddActor(textActorX);

		vtkTextActor textActorY = new vtkTextActor();
		textActorY.SetInput("Y");
		textActorY.GetTextProperty().SetColor(1, 0, 0);
		textActorY.GetTextProperty().ShadowOff();
		textActorY.GetPositionCoordinate().SetCoordinateSystemToWorld();
		textActorY.GetPositionCoordinate().SetValue(2, 15, 0);
		vtkPanel.GetRenderer().AddActor(textActorY);

		vtkTextActor textActorZ = new vtkTextActor();

		textActorZ.SetInput("Z");
		textActorZ.GetTextProperty().SetColor(1, 0, 0);
		textActorZ.GetTextProperty().ShadowOff();
		textActorZ.GetPositionCoordinate().SetCoordinateSystemToWorld();
		textActorZ.GetPositionCoordinate().SetValue(2, 0, 15);
		vtkPanel.GetRenderer().AddActor(textActorZ);
	}

	public void addImageModel(String key, AbstractImageModel image) {
		vtkPanel.GetRenderer().AddActor(image.getActor());
		vtkPanel.GetRenderer().AddActor(image.getOutlineActor());
		this.actors.put(key, image);
		vtkPanel.Render();
	}

	public vtkPanel getVtkPanel() {
		return vtkPanel;
	}

	public void setVtkPanel(vtkPanel vtkPanel) {
		this.vtkPanel = vtkPanel;
	}

	public SurfaceImageModel getSim() {
		return sim;
	}

	public void setSim(SurfaceImageModel sim) {
		this.sim = sim;
	}

	public void refresh() {
		vtkPanel.Render();
	}

	public void setBackgroundColor(Color newColor) {
		vtkPanel.GetRenderer().SetBackground((float) newColor.getRed() / 255,
                (float) newColor.getGreen() / 255,
                (float) newColor.getBlue() / 255);
		vtkPanel.Render();
    }

}
